package com.mytijian.code.service;

import com.alibaba.fastjson.JSON;
import com.mytijian.code.enums.CodeOperateEnum;
import com.mytijian.code.enums.MerchantOrderStatusEnum;
import com.mytijian.code.exceptions.MashangExceptionEnum;
import com.mytijian.code.model.CodeOperateLog;
import com.mytijian.code.model.Mcode;
import com.mytijian.code.model.MerchantOrder;
import com.mytijian.code.param.InvalidParam;
import com.mytijian.code.param.RefundSuccessParam;
import com.mytijian.code.param.SuitSuccessParam;
import com.mytijian.code.service.helper.TransactionHelper;
import com.mytijian.exception.BizSystemException;
import com.mytijian.openapi.adapter.alihalt.listener.AlihaltOutEventListenService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.TransactionStatus;
import org.springframework.util.CollectionUtils;

import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;

/**
 * Created by shjh on 2017/9/27.
 */
@Service
public class InvalidCodeServiceImpl implements InvalidCodeService {
    private Logger logger = LoggerFactory.getLogger(InvalidCodeServiceImpl.class);

    @Autowired
    private MerchantOrderService merchantOrderService;
    @Autowired
    private TransactionHelper transactionHelper;
    @Autowired
    private CodeService codeService;
    @Autowired
    private AlihaltOutEventListenService alihaltOutEventListenService;
    @Autowired
    private CodeOperateLogService codeOperateLogService;

    @Override
    public void acceptRefundSuccess(RefundSuccessParam param) {
        logger.info("订单退款开始param: " + JSON.toJSONString(param));
        MerchantOrder merchantOrder = merchantOrderService.selectByOuterId(param.getOuterId());
        if (!invalidValidParam(merchantOrder, param.getOuterId(), "退款")) {
            return;
        }

        TransactionStatus status = transactionHelper.beginTransaction();
        try {
            merchantOrderService.invalidOrder(merchantOrder.getId(), param.getRefundFee(), param.getCancelNum());

            invalidCode(merchantOrder, CodeOperateEnum.REFUND_CODE, null);
            transactionHelper.commit(status);

        } catch (Exception ex) {
            transactionHelper.rollback(status);
            throw new BizSystemException(MashangExceptionEnum.SYSTEM_ERROR, ex);
        }
        logger.info("订单退款结束");
    }

    @Override
    public void acceptSuitSuccess(SuitSuccessParam param) {
        logger.info("订单维权开始param: " + JSON.toJSONString(param));
        MerchantOrder merchantOrder = merchantOrderService.selectByOuterId(param.getOuterId());
        if (!invalidValidParam(merchantOrder, param.getOuterId(), "维权")) {
            return;
        }
        TransactionStatus status = transactionHelper.beginTransaction();
        try {
            merchantOrderService.invalidOrder(merchantOrder.getId(), param.getRefundFee(), null);

            invalidCode(merchantOrder, CodeOperateEnum.SUIT_CODE, param.getSuitResult());

            transactionHelper.commit(status);
        } catch (Exception ex) {
            transactionHelper.rollback(status);
            throw new BizSystemException(MashangExceptionEnum.SYSTEM_ERROR, ex);
        }
        logger.info("订单维权结束");
    }

    @Deprecated
    @Override
    public void acceptInvalid(InvalidParam param) {
        logger.info("订单作废开始param: " + JSON.toJSONString(param));
        MerchantOrder merchantOrder = merchantOrderService.selectByOuterId(param.getOuterId());
        if (!invalidValidParam(merchantOrder, param.getOuterId(), "作废")) {
            return;
        }
        TransactionStatus status = transactionHelper.beginTransaction();
        try {
            merchantOrderService.invalidOrder(merchantOrder.getId(), param.getRefundFee(), null);
            invalidCode(merchantOrder, CodeOperateEnum.INVALID_CODE, null);

            transactionHelper.commit(status);
        } catch (Exception ex) {
            transactionHelper.rollback(status);
            throw new BizSystemException(MashangExceptionEnum.SYSTEM_ERROR, ex);
        }

        logger.info("订单作废结束");
    }

    private boolean invalidValidParam(MerchantOrder merchantOrder, String outerId, String operate) {
        if (merchantOrder == null) {
            logger.info("订单" + operate + "结束,此订单{}码商处不存在", outerId);
            return false;
        }
        if (merchantOrder.getStatus() == MerchantOrderStatusEnum.UNNORMAL.getCode()) {
            logger.info("修改电子码有效期结束,此订单{}已作废", outerId);
            return false;
        }
        return true;
    }

    /**
     * 作废电子码
     */
    private void invalidCode(MerchantOrder merchantOrder, CodeOperateEnum operate, String suitResult) {
        List<Mcode> mcodes = codeService.listMcodeByOuterId(merchantOrder.getOuterId());
        if (CollectionUtils.isEmpty(mcodes)) {
            return;
        }

        saveInvalidCodeOperateLogs(operate, suitResult, mcodes);

        codeService.refundCodesByOrderId(merchantOrder.getOuterId());

        List<String> codes = mcodes.stream().map(needInvalidCode -> needInvalidCode.getCode()).collect(Collectors.toList());
        try {
            alihaltOutEventListenService.onMcodeDestory(codes);
        } catch (Exception e) {
            logger.warn("!!!调用阿里健康对接系统电子码销毁通知接口异常");
        }
    }

    private void saveInvalidCodeOperateLogs(CodeOperateEnum operate, String suitResult, List<Mcode> mcodes) {
        if (CollectionUtils.isEmpty(mcodes)) {
            return;
        }
        List<CodeOperateLog> codeOperateLogs = new ArrayList<>();
        for (Mcode mcode : mcodes) {
            codeOperateLogs.add(buildCodeOperateLog(operate, suitResult, mcode));
        }
        codeOperateLogService.batchSave(codeOperateLogs);
    }

    private CodeOperateLog buildCodeOperateLog(CodeOperateEnum operate, String suitResult, Mcode mcode) {
        CodeOperateLog codeOperateLog = new CodeOperateLog();
        codeOperateLog.setCode(mcode.getCode());
        codeOperateLog.setOperate(operate.getCode());
        if (operate == CodeOperateEnum.SUIT_CODE) {
            codeOperateLog.setSuitResult(suitResult);
        }
        codeOperateLog.setValidStart(mcode.getValidStart());
        codeOperateLog.setValidEnd(mcode.getValidEnd());
        codeOperateLog.setOuterId(mcode.getOuterId());
        return codeOperateLog;
    }
}
